import { _decorator, Collider2D, Component, ERaycast2DType, Node, PhysicsSystem2D, RaycastResult2D, Sprite, tween, Tween, UIOpacity, UITransform, Vec2, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Laser')
export class Laser extends Component {

    @property(Sprite)
    public laser_randerer: Sprite = null;
    @property(Node)
    public start_point: Node = null;
    @property(Node)
    public end_point: Node = null;

    public maxDistance: number = 2000;  // 激光的最大射程
    public speed: number = 10000;  // 激光的发射速度
    public laser_width: number = 20;
    public collisionConditionF: (co: Collider2D) => boolean = null;

    public end_hit: RaycastResult2D = null;

    private _calls: ((co: Collider2D) => void)[] = [];
    private _end: boolean = false;
    public setHitEventCallback(callback: (co: Collider2D) => void) {
        if (this._calls.indexOf(callback) != -1) {
            return;
        }
        this._calls.push(callback);
    }

    private isFiring: boolean = false;  // 激光是否在发射
    private laserDirection: Vec3 = new Vec3(1, 0, 0);  // 激光的方向
    private laserStartPosition: Vec3 = new Vec3(0, 0, 0);  // 激光的起始位置
    private uiTran: UITransform = null;

    private distance: number = 0;
    protected onEnable(): void {
        this.uiTran = this.node.getComponent(UITransform);
        this.node.getWorldPosition(this.laserStartPosition);
        this.updateLaserShow(this.laserStartPosition);

        // this.start_point.active = false;
        // this.end_point.active = false;
    }

    protected onDisable(): void {
        this._calls = [];
        this.isFiring = false;
        this.collisionConditionF = null;
        this.laser_width = 20;
        Tween.stopAllByTarget(this.node);
        this._end = false;
        this.end_hit = null;
        let opacity = this.getComponent(UIOpacity) || this.node.addComponent(UIOpacity);
        opacity.opacity = 255;
        this.start_point.active = true;
    }

    updateLaser(dt: number) {

        // 如果激光正在发射
        if (this.isFiring) {
            // 计算激光的目标位置
            this.distance += this.speed * dt;
            this.distance = Math.min(this.distance, this.maxDistance);

            // 计算新的目标点
            let newEndPoint = this.laserStartPosition.clone().add(this.laserDirection.normalize().multiplyScalar(this.distance));

            if (!this._end || !this.end_hit) {
                // 检查是否有碰撞
                this.checkCollisionPoint(newEndPoint);
            }

            if (this.end_hit) {
                const collisionPoint = this.end_hit.point;
                newEndPoint.set(collisionPoint.x, collisionPoint.y);
            }

            // 更新激光的显示
            this.updateLaserShow(newEndPoint);

        }
    }

    // 激光的开始发射
    public fire(worldPosition?: Vec3, direction?: Vec3) {
        this.isFiring = true;
        if (this._end) {
            worldPosition = this.laserStartPosition;
        }
        if (worldPosition) {
            this.laserStartPosition = worldPosition;  // 设置激光的发射位置
        }
        else {
            this.node.getWorldPosition(this.laserStartPosition);
        }
        if (direction) {

            this.laserDirection = direction.clone().normalize();  // 设置激光的发射方向
        }

        // 激光初始位置
        this.node.setWorldPosition(this.laserStartPosition);
        // this.start_point.active = true;
        // this.end_point.active = true;
    }


    // 更新激光的显示
    private updateLaserShow(newEndPoint: Vec3) {
        const start = this.laserStartPosition;
        const direction = newEndPoint.clone().subtract(start);

        // 更新激光的旋转和长度
        const angle = Math.atan2(direction.y, direction.x) * (180 / Math.PI);
        this.node.setRotationFromEuler(0, 0, angle);

        // 更新激光的长度
        this.uiTran.setContentSize(direction.length(), this.laser_width);
        this.end_point.setPosition(direction.length(), 0);
    }


    // 检查激光的路径上是否有物体阻挡
    private checkCollisionPoint(newEndPoint: Vec3) {
        const { x, y } = this.laserStartPosition;
        const start = new Vec2(x, y);

        // 发射射线检测碰撞 起点 终点
        let _ray = PhysicsSystem2D.instance.raycast(start, newEndPoint, ERaycast2DType.All);

        let ray = [..._ray];

        ray.sort((a, b) => {
            const distA = start.subtract(a.point).length(); // 计算距离
            const distB = start.subtract(b.point).length(); // 计算距离
            return distA - distB;  // 按照距离升序排序
        });

        for (let i = 0; i < ray.length; i++) {
            let hit = ray[i];
            if (hit.collider && !hit.collider.sensor) {
                if (this.collisionConditionF == null
                    || this.collisionConditionF(hit.collider)) {
                    // // 如果有碰撞，返回碰撞点
                    // const collisionPoint = hit.point;
                    // newEndPoint.set(collisionPoint.x, collisionPoint.y);
                    this._calls.forEach(call => {
                        call(hit.collider);
                    });

                    this.end_hit = hit;
                    return;
                }
            }
        }
    }

    LaserEndAimi(duration: number) {
        this._end = true;
        let opacity = null;
        tween(this.node).
            to(duration / 2, {}, {
                onStart: (target) => {
                    opacity = this.getComponent(UIOpacity) || this.node.addComponent(UIOpacity);
                },
                onUpdate: (target, ratio) => {
                    if (opacity) {
                        opacity.opacity = (1 - ratio) * 255 + 100;
                    }
                    // let dir = this.end_point.worldPosition.subtract(this.start_point.worldPosition);
                    // dir.multiplyScalar(ratio);
                    // this.laserStartPosition.add(dir);
                },
                easing: 'quintOut'
            }).to(duration / 2, {}, {
                onStart: (target) => {
                    this.start_point.active = false;
                },
                onUpdate: (target, ratio) => {
                    let dir = this.end_point.worldPosition.subtract(this.start_point.worldPosition);
                    dir.multiplyScalar(ratio);
                    this.laserStartPosition.add(dir);
                },
                easing: 'quintOut'
            }).start();
    }
}


